import matplotlib
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from datetime import datetime

# Specify a font that supports the required glyphs
# plt.rcParams['font.family'] = 'Arial Unicode MS'  # This font supports a wide range of Unicode characters

plt.style.use('ggplot')  # 更改绘图风格，R语言绘图库的风格
plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示

# 导入数据
columns = ['user_id', 'order_dt', 'order_products', 'order_amount']
# df = pd.read_table('./Files/CDNOW_master.txt', names=columns, sep='\s+')  # \s+ 匹配任意个空格
df = pd.read_csv('./Files/CDNOW_master.txt', names=columns, sep='\s+')


# print(df)
# print(df.info())


def get_month(date_str):
    date_str_new = str(date_str)
    date_obj = datetime.strptime(date_str_new, '%Y%m%d')
    # 修改日期部分为2024-01-01
    new_date_obj = date_obj.replace(day=1)

    return new_date_obj


# 数据预处理
df['order_date'] = pd.to_datetime(df['order_dt'], format='%Y%m%d')
df['month'] = df['order_dt'].map(get_month)
# df['month'] = df['order_date'].astype('datetime64[M]')
# print(df)
# print(df.info())

# 用户整体消费趋势分析
# 按月份统计产品购买数量、消费金额、消费次数和消费人数
plt.figure(figsize=(20, 12))
# 每月产品购买数量
plt.subplot(221)
df.groupby(['month'])['order_products'].sum().plot()
plt.title('每月的产品购买数量')

# 每月的消费金额
plt.subplot(222)
df.groupby(['month'])['order_amount'].sum().plot()
plt.title('每月的消费金额')

# 每月的消费次数
plt.subplot(223)
df.groupby(['month'])['user_id'].count().plot()
plt.title('每月的消费次数')

# 每月的消费人数
plt.subplot(224)
df.groupby(['month'])['user_id'].apply(lambda x: x.drop_duplicates().count()).plot()
plt.title('每月的消费人数')

plt.show()

# 用户个体消费分析
# 1.用户消费金额，消费次数(产品数量)描述统计
user_grouped = df.groupby(by='user_id')[['user_id', 'order_products', 'order_amount']].sum()
# print(user_grouped.describe())
# 从用户的角度：用户数量23570个，每个用户平均购买7个CD，但是中位数只有3，
# 并且最大购买量为1033，平均值大于中位数，属于典型的右偏分布(替购买量<7的用户背锅)
# 从消费金额角度：平均用户消费106，中位数43，并且存在土豪用户13990，结合分位数和最大值来看，平均数与75%分位数几乎相等，
# 属于典型的右偏分布，说明存在小部分用户（后面的25%）高额消费（这些用户需要给消费金额<106的用户背锅，只有这样才能使平均数维持在106）

# 绘制每个用户的产品的购买量与消费金额散点图
df.plot(x='order_products', y='order_amount', kind='scatter')
plt.show()
# 从图中可知，用户的消费金额与购买量呈现线性趋势，每个商品均价15左右
# 订单的极值点比较少（消费金额>1000，或者购买量大于60）,对于样本来说影响不大，可以忽略不记。

# 2.用户消费分布图
plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.xlabel('每个订单的消费金额')
df['order_amount'].plot(kind='hist', bins=50)
# bins:区间分数，影响柱子的宽度，值越大柱子越细。宽度=（列最大值-最小值）/bins
# #消费金额在100以内的订单占据了绝大多数

plt.subplot(122)
plt.xlabel('每个uid购买的数量')
df.groupby(by='user_id')['order_products'].sum().plot(kind='hist', bins=50)
# 图二可知，每个用户购买数量非常小，集中在50以内
# 两幅图得知，我们的用户主要是消费金额低，并且购买小于50的用户人数占据大多数（在电商领域是非常正常的现象）

plt.show()

# 3.用户累计消费金额占比分析（用户的贡献度）
# 进行用户分组，取出消费金额，进行求和、排序以及重置索引
user_cumsum = df.groupby(by='user_id')['order_amount'].sum().sort_values().reset_index()
# print(user_cumsum)

# 每个用户消费金额累加 累加器cumsum函数
user_cumsum['amount_cumsum'] = user_cumsum['order_amount'].cumsum()
# print(user_cumsum)

# 消费金额总值
amount_total = user_cumsum['amount_cumsum'].max()
user_cumsum['prop'] = user_cumsum.apply(lambda x: x['amount_cumsum'] / amount_total, axis=1)
# print(user_cumsum)
plt.figure(figsize=(12, 4))
plt.subplot(111)
user_cumsum['prop'].plot()
plt.show()
# 由图分析可知，前20000名用户贡献40%，剩余3500名用户贡献60%，（2/8原则）

# 用户消费行为
# 1.首购时间
# 进行用户分组，取最小的时间
plt.figure(figsize=(12, 4))
plt.subplot(121)
df.groupby(by='user_id')['order_date'].min().value_counts().plot()
# 有图可知，首次购买的用户量在1月1日~2月10日明显上升趋势，后续开始逐步下降

# 2.最后一次购买时间
plt.subplot(122)
df.groupby(by='user_id')['order_date'].max().value_counts().plot()
plt.show()

# 用户分层
# 1.构建RFM模型
# 透视表的使用（index:相当于groupby,values:取出的数据列，aggfunc:key值必须存在于values列中，并且必须跟随有效的聚合函数）
rfm = df.pivot_table(index='user_id',
                     values=['order_products', 'order_amount', 'order_date'],
                     aggfunc={
                         'order_date': 'max',
                         'order_products': 'sum',
                         'order_amount': 'sum'
                     })
print(rfm)

# 用每个用户的最后一次购买时间-日期列中的最大值，最后再转换成天数，小数保留一位
rfm['R'] = -(rfm['order_date'] - rfm['order_date'].max()) / np.timedelta64(1, 'D')
rfm.rename(columns={'order_products': 'F', 'order_amount': 'M'}, inplace=True)
print(rfm.head())


# RFM计算方式：每一列数据减去数据所在列的平均值，有正有负，根据结果值与1做比较，如果>=1,设置为1，否则0
def rfm_func(x):  # x:分别代表每一列数据
    level = x.apply(lambda x: '1' if x >= 1 else '0')
    label = level['R'] + level['F'] + level['M']
    d = {
        '111': '重要价值客户',
        '011': '重要保持客户',
        '101': '重要发展客户',
        '001': '重要挽留客户',
        '110': '一般价值客户',
        '010': '一般保持客户',
        '100': '一般发展客户',
        '000': '一般挽留客户'
    }
    result = d[label]
    return result


rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x: x - x.mean()).apply(rfm_func, axis=1)
print(rfm.head())

# 客户分层可视化
plt.figure(figsize=(12, 4))
plt.subplot(111)
for label, grouped in rfm.groupby(by='label'):
    x = grouped['F']
    y = grouped['R']
    plt.scatter(x, y, label=label)
plt.legend()  # 显示图例
plt.xlabel('F')
plt.ylabel('R')
plt.show()

# 新老，活跃，回流用户分析

# 新用户的定义是第一次消费。
# 活跃用户即老客，在某一个时间窗口内有过消费。
# 不活跃用户则是时间窗口内没有消费过的老客。
# 回流用户：相当于回头客的意思。
# 用户回流的动作可以分为自主回流与人工回流，自主回流指玩家自己回流了，而人工回流则是人为参与导致的。
print(df)
pivoted_counts = df.pivot_table(index='user_id', values='order_dt', columns='month', aggfunc='count').fillna(0)
print(pivoted_counts.head())

# 由于浮点数不直观，并且需要转成是否消费过即可，用0、1表示
df_purchase = pivoted_counts.map(lambda x: 1 if x > 0 else 0)
# apply:作用与dataframe数据中的一行或者一列数据
# applymap:作用与dataframe数据中的每一个元素
# map:本身是一个series的函数，在df结构中无法使用map函数，map函数作用于series中每一个元素的
print(df_purchase.head())


def set_state(data):
    state = []  # 存储用户18个月的状态（new|active|unactive|return|unreg）
    for i in range(18):
        if data[i] == 0:
            if len(state) == 0:
                state.append("unreg")
            else:
                if state[i - 1] == "unreg":
                    state.append("unreg")
                else:
                    state.append("unactive")
        else:
            if len(state) == 0:
                state.append("new")
            else:
                if state[i - 1] == "unactive":
                    state.append("return")
                elif state[i - 1] == "unreg":
                    state.append("new")
                else:
                    state.append("active")
        pass

    return pd.Series(state, df_purchase.columns)  # 值：status,列名：18个月份


purchase_states = df_purchase.apply(set_state, axis=1)
print(purchase_states.head())

# 把unreg状态用nan替换
purchase_states_ct = purchase_states.replace("unreg", np.NAN).apply(lambda x: pd.Series(x).value_counts())
print(purchase_states_ct.head())

# 数据可视化，面积图
purchase_states_ct.fillna(0).T.plot.area(figsize=(12, 5))
plt.show()
# 由图可知：灰色区域是不活跃用户，占比较大
# 前三个月新用户，还是活跃用户呈现了上升趋势，猜测由于活动造成的影响
# 3月份过后，紫色回流用户，红色活跃用户，都呈现下降趋势，并且趋于平稳状态
# 3月份过后，新用户量几乎没有大量增加


# 每月中回流用户占比情况（占所有用户的比例）
plt.figure(figsize=(12, 6))
rate = purchase_states_ct.fillna(0).T.apply(lambda x: x / x.sum(), axis=1)
plt.plot(rate['return'], label='return')
plt.plot(rate['active'], label='active')
plt.legend()
plt.show()
# 由图可知，前3个月，活跃用户占比比较大，维持在7%左右，而回流用户比例在上升，由于new用户还没有足够时间变成回流用户
# 4月份过后，不论是活跃用户，还是回流用户都呈现出下降趋势，但是回流用户依然高于活跃用户。
